/*---------------------------------------------------------------------
 * File name: hal_pwm.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "gd32f30x.h"
#include "hal_pwm.h"
#include "hal_config.h"
#if defined(USING_RT_THREAD)
#include <rtthread.h>
#endif
/*
*/
bool HAL_PWM::init(HAL_Timer *timer0, uint32_t cfg0)
{
  timer = timer0;
  cfg = cfg0;
  return config(cfg);
}
/*
*/
bool HAL_PWM::config(uint32_t cfg0)
{
  cfg &= ~HPWM_CFG_MASK;
  cfg |= cfg0 & HPWM_CFG_MASK;
  	
  /* OC config */
  timer_oc_parameter_struct timer_ocintpara;
  
  timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
  timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
  //OCP
  uint32_t tmp = HPWM_CFG_EXTRACT(cfg, OCP);
  if(tmp == HPWM_OCP(HIGH)) { 
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
  } else { 
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_LOW;
  }
  //OCNP
  tmp = HPWM_CFG_EXTRACT(cfg, OCNP);
  if(tmp == HPWM_OCNP(HIGH)) { 
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
  } else { 
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_LOW;
  }
  //OCIDS
  tmp = HPWM_CFG_EXTRACT(cfg, OCIDS);
  if(tmp == HPWM_OCIDS(SET)) { 
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
  } else {
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
  }
  //OCNIDS
  tmp = HPWM_CFG_EXTRACT(cfg, OCNIDS);
  if(tmp == HPWM_OCNIDS(SET)) { 
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_HIGH;
  } else {
    timer_ocintpara.ocidlestate  = TIMER_OCN_IDLE_STATE_LOW;
  }
  
  //Config
  uint32_t mode = HPWM_CFG_EXTRACT(cfg, MODE);
  tmp = HPWM_CFG_EXTRACT(cfg, CH);
  if(tmp & HPWM_CH(0)) { 
    timer_channel_output_config(timer->port, TIMER_CH_0, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_0, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_0, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(1)) { 
    timer_channel_output_config(timer->port, TIMER_CH_1, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_1, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(2)) { 
    timer_channel_output_config(timer->port, TIMER_CH_2, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_2, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_2, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_2, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(3)) { 
    timer_channel_output_config(timer->port, TIMER_CH_3, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_3, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_3, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);
  }
  return true;
}
/*
*/
void HAL_PWM::set_percent(int index, float percent0)
{
  percent[index] = percent0;
  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent[0]);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent[1]);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent[2]);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWM::set_percent(float *percent0)
{
  memcpy(percent, percent0, sizeof(float)*4);

  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent[0]);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent[1]);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent[2]);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWM::set_percent(int index, uint32_t percent0)
{
  percent1000[index] = percent0;
  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent1000[0] / 1000);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent1000[1] / 1000);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent1000[2] / 1000);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent1000[3] / 1000);
}
/*
*/
void HAL_PWM::set_percent(uint32_t *percent0)
{
  memcpy(percent1000, percent0, sizeof(uint32_t)*4);

  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent1000[0] / 1000);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent1000[1] / 1000);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent1000[2] / 1000);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent1000[3] / 1000);
}
